package com.sun.corba.se.impl.resolver ;

import org.omg.CORBA.portable.InputStream ;
import org.omg.CORBA.portable.OutputStream ;
import org.omg.CORBA.portable.ApplicationException ;
import org.omg.CORBA.portable.RemarshalException ;

import com.sun.corba.se.spi.ior.IOR ;
import com.sun.corba.se.spi.ior.IORFactories ;
import com.sun.corba.se.spi.ior.IORTemplate ;
import com.sun.corba.se.spi.ior.ObjectKey ;
import com.sun.corba.se.spi.ior.ObjectKeyFactory ;
import com.sun.corba.se.spi.ior.iiop.IIOPAddress ;
import com.sun.corba.se.spi.ior.iiop.IIOPProfileTemplate ;
import com.sun.corba.se.spi.ior.iiop.IIOPFactories ;
import com.sun.corba.se.spi.ior.iiop.GIOPVersion ;
import com.sun.corba.se.spi.logging.CORBALogDomains ;
import com.sun.corba.se.spi.orb.ORB ;
import com.sun.corba.se.spi.resolver.Resolver ;

import com.sun.corba.se.impl.logging.ORBUtilSystemException ;
import com.sun.corba.se.impl.orbutil.ORBUtility ;

public class BootstrapResolverImpl implements Resolver {
    private org.omg.CORBA.portable.Delegate bootstrapDelegate ;
    private ORBUtilSystemException wrapper ;

    public BootstrapResolverImpl(ORB orb, String host, int port) {
	wrapper = ORBUtilSystemException.get( orb, 
	    CORBALogDomains.ORB_RESOLVER ) ;

	// Create a new IOR with the magic of INIT
	byte[] initialKey = "INIT".getBytes() ;
	ObjectKey okey = orb.getObjectKeyFactory().create(initialKey) ;

	IIOPAddress addr = IIOPFactories.makeIIOPAddress( orb, host, port ) ;
	IIOPProfileTemplate ptemp = IIOPFactories.makeIIOPProfileTemplate(
	    orb, GIOPVersion.V1_0, addr);
	    
	IORTemplate iortemp = IORFactories.makeIORTemplate( okey.getTemplate() ) ;
	iortemp.add( ptemp ) ;

	IOR initialIOR = iortemp.makeIOR( (com.sun.corba.se.spi.orb.ORB)orb, 
	    "", okey.getId() ) ;

	bootstrapDelegate = ORBUtility.makeClientDelegate( initialIOR ) ;	
    }

    /**
     * For the BootStrap operation we do not expect to have more than one 
     * parameter. We do not want to extend BootStrap protocol any further,
     * as INS handles most of what BootStrap can handle in a portable way.
     *
     * @return InputStream which contains the response from the 
     * BootStrapOperation.
     */
    private InputStream invoke( String operationName, String parameter )
    { 
	boolean remarshal = true;

	// Invoke.

	InputStream inStream = null;

	// If there is a location forward then you will need
	// to invoke again on the updated information.
	// Just calling this same routine with the same host/port
	// does not take the location forward info into account.

	while (remarshal) {
	    org.omg.CORBA.Object objref = null ;
	    remarshal = false;

	    OutputStream os = (OutputStream) bootstrapDelegate.request( objref, 
		operationName, true);

            if ( parameter != null ) {
                os.write_string( parameter );
            }

	    try {
		// The only reason a null objref is passed is to get the version of
		// invoke used by streams.  Otherwise the PortableInterceptor
		// call stack will become unbalanced since the version of
		// invoke which only takes the stream does not call 
		// PortableInterceptor ending points.
		// Note that the first parameter is ignored inside invoke.

		inStream = bootstrapDelegate.invoke( objref, os);
	    } catch (ApplicationException e) {
		throw wrapper.bootstrapApplicationException( e ) ;
	    } catch (RemarshalException e) {
		// XXX log this
		remarshal = true;
	    }
	}

        return inStream;
    }

    public org.omg.CORBA.Object resolve( String identifier ) 
    {
	InputStream inStream = null ;
	org.omg.CORBA.Object result = null ;

	try { 
	    inStream = invoke( "get", identifier ) ;

	    result = inStream.read_Object();

	    // NOTE: do note trap and ignore errors.
	    // Let them flow out.
	} finally {
	    bootstrapDelegate.releaseReply( null, inStream ) ;
	}

	return result ;
    }

    public java.util.Set list()
    {
	InputStream inStream = null ;
	java.util.Set result = new java.util.HashSet() ;

	try {
	    inStream = invoke( "list", null ) ;

	    int count =	inStream.read_long();
	    for (int i=0; i < count; i++) 
		result.add( inStream.read_string() ) ;

	    // NOTE: do note trap and ignore errors.
	    // Let them flow out.
	} finally {
	    bootstrapDelegate.releaseReply( null, inStream ) ;
	}

	return result ;
    }
}
